package br.unicamp.ic.lis.dbvapi.domain;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.apache.commons.lang.StringUtils;

import br.unicamp.ic.lis.dbvapi.utils.StampUtils;

@Entity
@Table(name = "DBV")
public class DBV implements Serializable, Comparable<DBV> {

	private static final long serialVersionUID = -7197920227650244363L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "dbvid")
	private long id;

	@OneToOne
	private DBV parent;

	private String stamp;

	@Column(name = "nextChild")
	private String nextChild;

	@ManyToOne(fetch = FetchType.EAGER)
	private Scale scale;

	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "creationDate")
	private Date creationDate;

	public DBV() {

	}

	public DBV(DBV parent) {
		this.parent = parent;
		this.creationDate = new Date();
		if (parent != null) {
			this.scale = parent.getScale();
		}
	}

	public DBV(DBV parent, Scale scale) {
		this.parent = parent;
		this.creationDate = new Date();
		this.scale = scale;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getStamp() {
		return stamp;
	}

	public void setStamp(String stamp) {
		this.stamp = stamp;
	}

	public Date getCreationDate() {
		return creationDate;
	}

	public void setCreationDate(Date creationDate) {
		this.creationDate = creationDate;
	}

	public DBV getParent() {
		return parent;
	}

	public void setParent(DBV parent) {
		this.parent = parent;
	}

	public String getNextChild() {
		return nextChild;
	}

	public void setNextChild(String nextChild) {
		this.nextChild = nextChild;
	}

	public Scale getScale() {
		return scale;
	}

	public void setScale(Scale scale) {
		this.scale = scale;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (int) (id ^ (id >>> 32));
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		DBV other = (DBV) obj;
		if (id != other.id) {
			return false;
		}
		return true;
	}

	@Override
	public String toString() {
		Long parentId = null;
		if (this.getParent() != null) {
			parentId = this.getParent().getId();
		}
		return "DBV [id=" + id + ", parent=" + parentId + ", stamp=" + stamp
				+ ", nextChild=" + nextChild + ", scale=" + scale + "]";
	}

	@Override
	public int compareTo(DBV other) {
		final int BEFORE = -1;
		final int EQUAL = 0;
		final int AFTER = 1;

		if (StringUtils.equalsIgnoreCase(this.getStamp(), other.getStamp())) {
			return EQUAL;
		}

		List<String> thisChainStamp = StampUtils.getStampChainAsList(this
				.getStamp());
		List<String> otherChainStamp = StampUtils.getStampChainAsList(other
				.getStamp());

		if (thisChainStamp.size() < otherChainStamp.size()) {
			return BEFORE;
		} else if (thisChainStamp.size() > otherChainStamp.size()) {
			return AFTER;
		} else {
			for (int i = 0; i < thisChainStamp.size(); i++) {
				int thisValueAsInt = Integer.valueOf(thisChainStamp.get(i));
				int otherValueAsInt = Integer.valueOf(otherChainStamp.get(i));
				if (thisValueAsInt < otherValueAsInt) {
					return BEFORE;
				}
			}
			return AFTER;
		}
	}
}
